home *** CD-ROM | disk | FTP | other *** search
- /*________________________________________________________
-
- File: Backwash.c
-
- C source for a printing extension that adds a
- QuickDraw picture to each page despooled.
-
- Dave Hersey
- Apple Developer Technical Support
-
- 11/11/92 - dmh - Created.
- 1/28/93 - dmh - Cleaned up for a5 seed CD.
- 3/26/93 - dmh - Updated for b1c2 (Translator changes).
- 8/24/93 - dmh - Updated for b2.
- - The picture is now rolled into the spool
- file as a resource, and applied to each
- page during despooling.
- - Added a TextEdit compatibility mode which
- strips out the white rectangles drawn by
- apps which use TextEdit to print (like
- TeachText).
- - The "intensity" panel item actually
- functions now.
- - Switched to Exception.h assertion stuff
- for error checking.
- 9/09/93 - dmh - AddBackwash now displays progress info.
- 12/18/93 - dmh - Updated for b3.
- 3/22/94 - dmh - Updated for b4.
- 5/03/94 - dmh - Updated for f2.
- - BWDespoolPage can be passed a nil format/shape.
- - The flattened shape resource is no longer purgeable.
- It wasn't making it back from GXDespoolResource
- without getting purged.
- 6/14/96 - cn - Updated to support Universal Interfaces 2.1.
-
- (Note: all functions are in the Mark menu.)
-
- __________________________________________________________*/
-
- #include "Backwash.h"
-
-
- /*******************************************************************
- __Startup__ contains our jump table to the overrides.
-
- ********************************************************************/
- #if defined(__MWERKS__)
- asm void __Startup__(void)
- {
- DC.L 0 // GX needs this
-
- JMP BWInitialize // (offset = 4)
- JMP BWShutDown // (offset = 8)
- JMP BWJobPrintDialog // (offset = 12)
- JMP BWHandlePanelEvent // (offset = 16)
- JMP BWCreateSpoolFile // (offset = 20)
- JMP BWDespoolPage // (offset = 24)
- JMP BWCloseSpoolFile // (offset = 28)
-
- RTS // this is needed so __Startup__ symbol works
- }
- #endif
-
-
- /*******************************************************************
- MyInitDataHandle is used to initialize any global data we need
- from our GXInitialize message override. .
-
- ********************************************************************/
-
- void MyInitDataHandle( MyDataHdl dataHandle )
- {
- (**dataHandle).backwashShape = nil;
- }
-
-
- /*******************************************************************
- GetBackwashShape returns the backwash shape from the structure
- whose handle is stored ing the MessageHandler InstanceContext.
-
- ********************************************************************/
- gxShape GetBackwashShape ( void )
- {
- MyDataHdl dataHandle;
- dataHandle = (MyDataHdl) GetMessageHandlerInstanceContext();
- return (**dataHandle).backwashShape;
- }
-
-
- /*******************************************************************
- BWInitialize is our override for the GXInitialize message.
- In here, you shouldn't initialize anything directly-- call
- InitGlobalData for that. Once you create the A5 world with
- NewMessageGlobals, you can access your global data just like
- you were an app. Whenever you're called, your global data will
- be valid.
-
- ********************************************************************/
-
- OSErr BWInitialize()
- {
- OSErr err;
- MyDataHdl dataHandle;
-
- /*
- Create a new temporary memory handle, initialize
- it, and store it as the message handler's instance
- context.
- */
-
- dataHandle = (MyDataHdl) TempNewHandle(sizeof(MyDataRec),&err);
-
- if (err == noErr)
- {
- MyInitDataHandle(dataHandle);
- SetMessageHandlerInstanceContext(dataHandle);
- }
-
- return err;
- }
-
-
- /*******************************************************************
- BWShutDown is our override for the GXShutDown message. We
- simply throw away our A5 world.
-
- ********************************************************************/
-
- OSErr BWShutDown()
- {
- MyDataHdl dataHandle;
-
- /*
- Retrieve the message handler's instance context. If the
- value returned isn't nil, it's a handle that we stored
- earlier. Dispose of the handle and set the instance
- context to nil to "clear" it.
- */
-
- dataHandle = (MyDataHdl) GetMessageHandlerInstanceContext();
-
- if (dataHandle != nil)
- {
- DisposeHandle((Handle) dataHandle);
- SetMessageHandlerInstanceContext(nil);
- }
-
- return noErr;
- }
-
-
- /*******************************************************************
- BWJobPrintDialog is our override for GXJobPrintDialog. All we
- do is set up our panel and then forward the message.
-
- ********************************************************************/
-
- OSErr BWJobPrintDialog(gxDialogResult *dlogResult)
- {
- OSErr err;
-
- err = SetUpPrintPanel();
-
- if (!err)
- err = Forward_GXJobPrintDialog(dlogResult);
-
- return err;
- }
-
-
- /*******************************************************************
- BWHandlePanelEvent is our override for GXHandlePanelEvent.
- If the event is one of ours, we handle it. Otherwise, we
- just forward it down the chain.
-
- ********************************************************************/
-
- OSErr BWHandlePanelEvent(gxPanelInfoRecord *panelInfo)
- {
- OSErr err = noErr;
- GrafPtr oldPort;
- DialogPtr pDlg;
- StandardFileReply reply;
- SFTypeList typeList;
- BackwashCollection backwashConfig;
- Handle hItem;
- Rect itemRect;
- short itemType, oldResFile;
-
- // Make sure that our resource file is at the top of the chain.
-
- oldResFile = CurResFile();
- UseResFile(GXGetMessageHandlerResFile());
-
-
- // Set our current QuickDraw port to the dialog.
-
- pDlg = panelInfo->pDlg;
- GetPort(&oldPort);
- SetPort(pDlg);
-
- switch (panelInfo->panelEvt)
- {
-
- // If our panel is opening, go do any initialization we need to.
-
- case gxPanelOpenEvt:
- OpenBackwashPanel(pDlg, panelInfo->itemCount);
- break;
-
-
- // If the user hits the "Select Picture" button, prompt them for a file to load.
- // If they select one, get our old collection item, move the FSSpec info to it,
- // and replace the old collection item with our modified one.
-
- case gxPanelHitEvt:
- if (panelInfo->itemHit == (panelInfo->itemCount + d_SelectPicture))
- {
-
- // Have the user select the PICT file to load.
-
- typeList[0] = 'PICT';
- StandardGetFile(nil, 1, typeList, &reply);
- require(reply.sfGood, UserCancelledFileDialog);
-
-
- // Get the old "Backwash settings" collection item, and update the file reference.
-
- err = GetJobCollectionItem(&backwashConfig,
- nil,
- kBackwashCollectionType,
- kBackwashSettingsID);
-
- nrequire(err, GetSettings_Failed);
-
- backwashConfig.haveFileInfo = true;
- BlockMove(&reply.sfFile, &backwashConfig.fileInfo, sizeof(FSSpec));
-
-
- // Replace the old collection item with the updated one.
-
- err = AddCollectionItem(GXGetJobCollection(GXGetJob()),
- kBackwashCollectionType,
- kBackwashSettingsID,
- sizeof(BackwashCollection),
- &backwashConfig);
-
- nrequire(err, StoreSettings_Failed);
-
-
- // Update the file name in our dialog.
-
- GetDItem(panelInfo->pDlg, panelInfo->itemCount +d_FileNameItem,
- &itemType, &hItem, &itemRect);
-
- SetIText(hItem, backwashConfig.fileInfo.name);
- }
- break;
-
-
- // If our panel is activating/deactivating or if the focus (which
- // section of the dialog is active) has changed we need to activate
- // our editText field appropriately.
-
- case gxPanelActivateEvt:
- case gxPanelDeactivateEvt:
- case gxPanelIconFocusEvt:
- case gxPanelPanelFocusEvt:
- if ((((DialogPeek) pDlg)->editField +1) == (panelInfo->itemCount +d_Intensity))
- {
- if (panelInfo->panelEvt == gxPanelPanelFocusEvt)
- TEActivate(((DialogPeek) pDlg)->textH);
- else
- TEDeactivate(((DialogPeek) pDlg)->textH);
- }
- break;
- }
-
- // Jump points for misc. error conditions follow.
-
- UserCancelledFileDialog:
- GetSettings_Failed:
- StoreSettings_Failed:
-
-
- // Finally, restore the original QuickDraw GrafPort and return.
-
- SetPort(oldPort);
- UseResFile(oldResFile);
- return err;
- }
-
-
- /*******************************************************************
- BWCreateSpoolFile is our override for GXCreateSpoolFile.
- It just gets our user settings collection item, sees if we're
- supposed to do anything, and if so, adds a gxShape version of
- the selected PICT to the spool file.
-
- ********************************************************************/
-
- OSErr BWCreateSpoolFile(FSSpecPtr anFSSpec, long createOptions, gxSpoolFile *theSpoolFile)
- {
- OSErr err;
- BackwashCollection backwashConfig;
-
- // Forward the message so that the spool file is created for us.
-
- err = Forward_GXCreateSpoolFile(anFSSpec, createOptions, theSpoolFile);
- nrequire(err, ForwardMessage_Failed);
-
- // Get our collection item and see if we're enabled and have file info. If
- // so, add the backwash picture to the spool file. Note that if we don't
- // find our collection item we don't try to add the backwash. The user may
- // not be printing with dialogs, so you have to deal with this situation…
- // Also, if we get an error when we try to add the Backwash shape, we
- // ignore the error but turn ourself off by removing our settings collection
- // item. This way, printing can continue, and BWDespoolPage won't be
- // confused when there's no Backwash shape in the print file.
-
- err = GetJobCollectionItem(&backwashConfig,
- nil,
- kBackwashCollectionType,
- kBackwashSettingsID);
-
- if (!err && backwashConfig.addBackwash && backwashConfig.haveFileInfo)
- {
- err = (OSErr) AddBackwash(&backwashConfig.fileInfo, (short) backwashConfig.intensity, *theSpoolFile);
- require(err, BackwashAdded);
-
- RemoveCollectionItem(GXGetJobCollection(GXGetJob()),
- kBackwashCollectionType,
- kBackwashSettingsID);
-
- err = noErr;
- }
- else
- if (err == collectionItemNotFoundErr)
- err = noErr;
-
- BackwashAdded:
- ForwardMessage_Failed:
-
- return err;
- }
-
-
- /*******************************************************************
- BWDespoolPage is our override for the GXDespoolPage message.
- We check to see if the user is adding a backwash, and if so,
- retrieve the flattened shape from the spool file and apply it
- to each page. For efficiency, we only retrieve the shape once,
- and then reference it via our instance-global, iBackwashShape. That
- shape is latered disposed of in BWCloseSpoolFile.
-
- ********************************************************************/
-
- OSErr BWDespoolPage(gxSpoolFile theSpoolFile, long thePageNum,
- gxFormat theFormat, gxShape *thePage,
- Boolean *formatChanged)
- {
- OSErr anOSErr;
- gxGraphicsError grErr;
- Handle vpListHdl, gxShapeHdl = nil;
- gxRectangle pBounds;
- Fixed cx, cy, px, py;
- long numViewPorts;
- BackwashCollection backwashConfig;
- gxShape iBackwashShape ;
-
- iBackwashShape = GetBackwashShape() ;
-
- // Forward the message so that we get the page shape, then retrieve our
- // "Backwash settings" collection item.
-
- anOSErr = Forward_GXDespoolPage(theSpoolFile, thePageNum, theFormat, thePage, formatChanged);
- nrequire((grErr = (gxGraphicsError) anOSErr), ForwardMessage_Failed);
- require((theFormat != nil) && (thePage != nil), NotAddingBackwash);
-
- grErr = GetJobCollectionItem(&backwashConfig,
- nil,
- kBackwashCollectionType,
- kBackwashSettingsID);
-
- require_action((!grErr && backwashConfig.addBackwash && backwashConfig.haveFileInfo),
- NotAddingBackwash, grErr = noErr;);
-
-
- // If we're in "TextEdit Compatibility" mode, remove white rectangles from the
- // page shape.
-
- if (backwashConfig.useTextEditMode)
- RemoveWhiteRects(*thePage);
-
-
- // If we need to load the flattened shape resource, do so. Note that we only
- // need to do this on the first page. Thereafter, the shape reference is in
- // our instance-global.
-
- if (iBackwashShape == nil)
- {
- anOSErr = Send_GXDespoolResource(theSpoolFile, kBackwashCollectionType, r_BackwashPICTID, &gxShapeHdl);
- nrequire((grErr = (gxGraphicsError) anOSErr), DespoolResource_Failed);
- }
-
-
- // If we haven't already, unflatten the Backwash shape. We need a
- // viewport list to unflatten the shape, so we get the current page's
- // viewport list and use that.
-
- if (iBackwashShape == nil)
- {
-
- numViewPorts = GXGetShapeViewPorts(*thePage, nil);
-
- vpListHdl = TempNewHandle(numViewPorts * sizeof(gxViewPort), &anOSErr);
- grErr = (gxGraphicsError) anOSErr;
- nrequire_action(grErr, TempNewHandle_Failed, ReleaseResource(gxShapeHdl););
-
- HLock(vpListHdl);
- GXGetShapeViewPorts(*thePage, (gxViewPort *) *vpListHdl);
- iBackwashShape = HandleToShape(gxShapeHdl, numViewPorts, (gxViewPort *) *vpListHdl);
- DisposHandle(vpListHdl); // all done with this.
-
- if (gxShapeHdl)
- ReleaseResource(gxShapeHdl); // all done with this-- remember, it's a resource!
-
- nrequire(GXGetGraphicsError(&grErr), CouldNotSetUpShape);
- }
-
-
- // Now we get the page dimensions from the current page format. We use this
- // and the shape's bounds to center the picture on the page. Once we've done
- // that, we add the GX picture shape behind all the other shapes in our page
- // shape and return.
-
- GXGetFormatDimensions(theFormat, &pBounds, nil);
- grErr = GXGetJobError(GXGetJob());
- nrequire(grErr, GetFormatDims_Failed);
-
- cx = pBounds.left + (pBounds.right - pBounds.left) >>1;
- cy = pBounds.top + (pBounds.bottom - pBounds.top) >>1;
-
- GXGetShapeBounds(iBackwashShape, 0, &pBounds);
- px = pBounds.left + (pBounds.right - pBounds.left) >>1;
- py = pBounds.top + (pBounds.bottom - pBounds.top) >>1;
- GXMoveShapeTo(iBackwashShape, cx-px, cy-py);
-
- GXSetPictureParts(*thePage, 1, 0, 1, &iBackwashShape, nil, nil, nil);
- GXGetGraphicsError(&grErr);
-
-
- // Jump points for misc. error conditions follow.
-
- GetFormatDims_Failed:
- CouldNotSetUpShape:
- TempNewHandle_Failed:
- DespoolResource_Failed:
- NotAddingBackwash:
- ForwardMessage_Failed:
-
- return grErr;
- }
-
-
- /*******************************************************************
- BWCloseSpoolFile is our override for the GXCloseSpoolFile
- message. If the instance-global shape "iBackwashShape" is not nil, we
- dispose of it. Remember that we initialized it to nil in
- BWInitialize, so the only way it can be non-nil is if we just
- used it during despooling.
-
- ********************************************************************/
-
- OSErr BWCloseSpoolFile(gxSpoolFile theSpoolFile, long closeOptions)
- {
- gxShape iBackwashShape ;
-
- iBackwashShape = GetBackwashShape() ;
-
- // Dispose of the shape and "nil out" our global, if necessary.
- // Then, forward the message so that the spool file is closed.
-
- if (iBackwashShape != nil)
- {
- GXDisposeShape(iBackwashShape);
- iBackwashShape = nil;
- }
-
- return Forward_GXCloseSpoolFile(theSpoolFile, closeOptions);
- }
-
-
- /*******************************************************************
- SetUpPrintPanel sets up our print panel, adding a default
- "Backwash settings" collection item to the job collection if
- there isn't already one. This collection item has the values
- we'll use to set up our panel's controls.
-
- ********************************************************************/
-
- OSErr SetUpPrintPanel()
- {
- OSErr err;
- gxPanelSetupRecord panelSetupRec;
- BackwashCollection backwashConfig;
-
- // Get the job collection and try to find our backwash settings.
-
- err = GetJobCollectionItem(&backwashConfig,
- nil,
- kBackwashCollectionType,
- kBackwashSettingsID);
-
-
- // If our collection item (settings) don't exist yet, create a default
- // collection item and add that to the job collection.
-
-
- if (err == collectionItemNotFoundErr)
- {
- FSSpec dafaultFSSpec;
-
-
- dafaultFSSpec.vRefNum = 0;
- dafaultFSSpec.parID = 0;
- BlockMoveData ("\pNone", dafaultFSSpec.name, 5);
-
- backwashConfig.intensity = kDefaultIntensity;
- backwashConfig.addBackwash = kDontAddBackwash;
- backwashConfig.useTextEditMode = false;
- backwashConfig.haveFileInfo = false;
- backwashConfig.fileInfo = dafaultFSSpec ;
-
- err = AddCollectionItem(GXGetJobCollection(GXGetJob()),
- kBackwashCollectionType,
- kBackwashSettingsID,
- sizeof(BackwashCollection),
- &backwashConfig);
- }
-
- nrequire(err, StoreSettings_Failed);
-
-
- // Now do the actual panel set up.
-
- panelSetupRec.panelResId = r_BackwashPanel; // Which panel resource?
- panelSetupRec.resourceRefNum = GXGetMessageHandlerResFile(); // Where is it?
- panelSetupRec.refCon = 0; // We don't use this.
- panelSetupRec.panelKind = gxExtensionPanel; // This is an extension panel.
-
- err = GXSetupDialogPanel(&panelSetupRec);
-
-
- StoreSettings_Failed:
-
- return err;
- }
-
-
- /*******************************************************************
- OpenBackwashPanel handles non-'xdtl' item initialization when
- we open our panel. Note that our items will be offset from
- itemCount. (So, if we want item #5 in our DITL, we pass
- itemCount +5 to GetDItem.)
-
- The only non-'xdtl' item we have in our panel is the PICTfile
- name. We initialize that here.
-
- ********************************************************************/
-
- void OpenBackwashPanel(DialogPtr pDlg, short itemCount)
- {
- BackwashCollection backwashConfig;
- Handle hItem;
- Rect itemRect;
- short itemType;
-
- // Initialize the current file name displayed, based on the
- // settings in our backwash collection item.
-
- GetJobCollectionItem(&backwashConfig,
- nil,
- kBackwashCollectionType,
- kBackwashSettingsID);
-
- GetDItem(pDlg, itemCount +d_FileNameItem, &itemType, &hItem, &itemRect);
- SetIText(hItem, backwashConfig.fileInfo.name);
- }
-
-
- /*******************************************************************
- AddBackwash is the routine we call at GXCreateSpoolFile time
- to actually add the backwash to our spool file. We pass in
- info on where the PICT file is, the intensity the user
- requested (as an integral percentage 0-100), and the spool
- file reference.
-
- ********************************************************************/
-
- gxGraphicsError AddBackwash(FSSpecPtr fileInfo, short theIntensity, gxSpoolFile theSpoolFile)
- {
- gxGraphicsError grErr;
- Rect pictBounds, itemRect;
- PicHandle backwashPict;
- Point patStretchPoint; // this means "don't stretch."
- Handle textHdl, gxShapeHdl = nil;
- gxShape gxPictShape;
- short resAttribs, oldResFile, ourResFile, itemKind;
- Str255 statMsg;
- DialogPtr theMessageDlog;
- unsigned long endTicks;
- GrafPtr oldPort;
-
-
- patStretchPoint.h = 1;
- patStretchPoint.v = 1;
-
- GetPort(&oldPort);
- oldResFile = CurResFile();
- ourResFile = GXGetMessageHandlerResFile();
- UseResFile(ourResFile);
-
-
- // Load the dialog that we'll display status messages in. Note that we
- // CANNOT use GXAlertTheUser or GXReportStatus in this routine, because
- // those only work when the Finder or PrinterShare GX are the active
- // applications (when we're spooling, the user's app is active.) Load
- // our first status string, and show/update the dialog.
-
- theMessageDlog = GetNewDialog(r_BackwashStatus, nil, (WindowPtr) -1);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadDialog);
- GetDItem(theMessageDlog, d_StatusFieldItem, &itemKind, &textHdl, &itemRect);
-
- GetIndString(statMsg, r_BackwashStatus, s_StatusLoadPict);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadString);
- SetIText(textHdl, statMsg);
- SetPort(theMessageDlog);
- PositionWindow(theMessageDlog, true, n_dlogLevel);
- DrawDialog(theMessageDlog);
-
-
- // Load the picture from disk. If we can't load it, we display a message
- // saying so, and then exit the routine after 3 seconds.
-
- GXJobIdle();
- backwashPict = LoadAPict(fileInfo);
-
- UseResFile(ourResFile);
- nrequire(backwashPict, PictureLoaded);
- GetIndString(statMsg, r_BackwashStatus, s_PictureNotLoaded);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadString);
- SetIText(textHdl, statMsg);
-
- SysBeep(0);
- endTicks = TickCount() + (3 * 60);
-
- while (endTicks > TickCount())
- GXJobIdle();
-
- require_action(backwashPict, CouldNotLoadPICT, grErr = nilHandleErr;);
-
-
- // Create a shape to store our converted PICT in, load and display another
- // status string, and then convert the PICT into a QuickDraw GX shape.
-
- PictureLoaded:
-
- pictBounds = (*backwashPict)->picFrame;
- gxPictShape = GXNewShape(gxPictureType); // shape to store picture in.
- nrequire_action(GXGetGraphicsError(&grErr), CouldNotCreateShape,
- KillPicture(backwashPict););
-
- UseResFile(ourResFile);
- GetIndString(statMsg, r_BackwashStatus, s_ConvertPict);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadString);
- SetIText(textHdl, statMsg);
-
- GXJobIdle();
-
- GXConvertPICTToShape(backwashPict, /* this is the original. */
- gxDefaultOptionsTranslation, /* use default settings. */
- &pictBounds, /* source/dest bounds. */
- &pictBounds,
- patStretchPoint, /* how to stretch (don't). */
- gxPictShape, /* the destination. */
- nil); /* we don't want details. */
-
- KillPicture(backwashPict); // original is converted so kill it.
-
- nrequire_action(GXGetGraphicsError(&grErr), CouldNotConvertShape,
- GXDisposeShape(gxPictShape););
-
-
- // Load and display another status string, lighten the GX picture shape as we
- // need to, and flatten the shape into a handle.
-
- UseResFile(ourResFile);
- GetIndString(statMsg, r_BackwashStatus, s_SetShapeIntensity);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadString);
- SetIText(textHdl, statMsg);
-
- GXJobIdle();
-
- UseResFile(ourResFile);
- grErr = SetShapeIntensity(gxPictShape, theIntensity);
- nrequire_action(grErr, CouldNotSetShapeIntensity, GXDisposeShape(gxPictShape););
- gxShapeHdl = ShapeToHandle(gxPictShape);
- grErr = (gxGraphicsError) MemError();
- GXDisposeShape(gxPictShape); // all done with this.
- nrequire(grErr, CouldNotFlattenShape);
-
-
- // Load and display our last status string, and add the shape as a resource in
- // the spool file. After adding it, update the resource so it's marked
- // "sysHeap." We do this so that the resource won't be loaded into
- // PrinterShare GX's heap at despool time. Since the data may be large, and
- // PrinterShare GX's heap is small, this will make things work better.
-
- GetIndString(statMsg, r_BackwashStatus, s_SpoolShapeResource);
- nrequire((grErr = (gxGraphicsError) ResError()), CouldNotLoadString);
- SetIText(textHdl, statMsg);
-
- GXJobIdle();
-
- grErr = Send_GXSpoolResource(theSpoolFile, gxShapeHdl, kBackwashCollectionType, r_BackwashPICTID);
- nrequire_action(grErr, CouldNotAddShape, DisposHandle(gxShapeHdl););
-
- resAttribs = GetResAttrs(gxShapeHdl);
- SetResAttrs(gxShapeHdl, resAttribs | resSysHeap);
- ChangedResource(gxShapeHdl);
- WriteResource(gxShapeHdl);
-
-
- // Finally release the resource (DON'T call DisposHandle on it!!), dispose of
- // our dialog, and return.
-
- ReleaseResource(gxShapeHdl);
-
-
- // Jump points for misc. error conditions follow.
-
- CouldNotAddShape:
- CouldNotFlattenShape:
- CouldNotSetShapeIntensity:
- CouldNotConvertShape:
- CouldNotCreateShape:
- CouldNotLoadPICT:
- CouldNotLoadString:
-
- SetPort(oldPort);
- DisposDialog(theMessageDlog);
-
- CouldNotLoadDialog:
-
- UseResFile(oldResFile);
- return grErr;
- }
-
-
- /*******************************************************************
- RemoveWhiteRects is the routine which strips white rectangles
- out of a page shape if we're in "TextEdit compatibility" mode.
- Apps which print text by using TextEdit and calling TEUpdate
- inadvertently add white rectangles behind the text they're
- drawing. This is because TEUpdate erases before it draws, and
- this erasure is translated into a white rectangle by GX. It's
- as if you drew a white rectangle shape (to erase) and then
- drew the text on top of that. This is yet another reason why
- DTS recommends that you not use TextEdit for printing.
-
- This routine calls itself recursively if a picture is passed.
- The return value for each call indicates whether or not you
- should remove the shape passed. The original caller is
- expected to pass a picture in, so it need not worry about the
- boolean value returned. (It should never be set, since a
- picture ≠ a white rect.)
-
- ********************************************************************/
-
- Boolean RemoveWhiteRects(gxShape theShape)
- {
- gxGraphicsError grErr = noErr;
- gxShapeType typeOfShape;
- gxShape nextShape;
-
- // Get the type of shape we were passed. If it's a picture shape,
- // get the number of parts in the picture.
-
- require(theShape, ShapeIsNIL);
- typeOfShape = GXGetShapeType(theShape);
-
- if (typeOfShape == gxPictureType)
- {
- long idx, numParts;
-
- numParts = GXGetPicture(theShape, nil, nil, nil, nil);
-
-
- // Loop through each picture item. If RemoveWhiteRects says it's a
- // white rectangle, remove it. When we remove a picture item, we
- // must decrement both the picture item index and the number of
- // items in the picture. That way, our loop still works.
-
- for (idx = 1; idx <= numParts; idx ++)
- {
- GXGetPictureParts(theShape, idx, 1, &nextShape, nil, nil, nil);
-
- if (RemoveWhiteRects(nextShape))
- {
- GXSetPictureParts(theShape, idx, 1, 0, nil, nil, nil, nil);
- idx -= 1;
- numParts -= 1;
- }
- }
- }
- else
-
- // We weren't passed a picture. See if it's a white rectangle which is being
- // "source copied." If so, return true-- this may be a TextEdit erasure.
-
- if (typeOfShape == gxRectangleType)
- {
- gxColor shapeColor;
- gxTransferMode shapeTransfer;
-
- GXGetShapeColor(theShape, &shapeColor);
- GXGetShapeTransfer(theShape, &shapeTransfer);
-
- if ((shapeColor.element.rgb.red == 0xFFFF) &&
- (shapeColor.element.rgb.green == 0xFFFF) &&
- (shapeColor.element.rgb.blue == 0xFFFF) &&
- (shapeTransfer.component[0].mode == gxCopyMode))
- return true;
- }
-
- ShapeIsNIL:
-
- return false;
- }
-
-
- /*******************************************************************
- SetShapeIntensity is a routine which lightens the shape passed
- based on the percentage specified. For example, an intensity
- of 100 (100%) means that the shape should appear normal. At
- 50, (50%) the shape will be half as dark, at 0 (0%) the shape
- would simply fade to white.
-
- This routine calls itself recursively if a picture is passed.
- For each item in the shape passed, (and all items contained in
- sub-pictures), the shape's ink is set to blend mode, and the
- item is blended by the percentage passed. Since the background
- during printing is white, this effectively fades a shape to
- white.
-
- ********************************************************************/
-
- gxGraphicsError SetShapeIntensity(gxShape theShape, short theIntensity)
- {
- gxGraphicsError grErr = noErr;
- gxShapeType typeOfShape;
- gxShape nextShape;
-
- // Get the type of shape we were passed. If it's a picture shape,
- // get the number of parts in the picture.
-
- require(theShape, ShapeIsNIL);
- require((theIntensity != 100), UsingFullIntensity);
- typeOfShape = GXGetShapeType(theShape);
-
- if (typeOfShape == gxPictureType)
- {
- long idx, numParts;
-
- numParts = GXGetPicture(theShape, nil, nil, nil, nil);
-
-
- // For each item in the picture, set the shape's intensity.
-
- for (idx = 1; !grErr && (idx <= numParts); idx ++)
- {
- GXGetPictureParts(theShape, idx, 1, &nextShape, nil, nil, nil);
- grErr = SetShapeIntensity(nextShape, theIntensity);
- }
- }
- else
-
- // We weren't passed a picture. Get the ink of this shape and set its
- // first (and only) transfer mode to "blend", maximize and minimize all
- // the bounding values, and set the transfer's operand to the percentage
- // passed in (scaled so that it's between 0 and 0xFFFF). Finally, set
- // the shape's transfer to this new value.
-
- {
- gxTransferMode shapeTransfer;
-
- GXGetShapeTransfer(theShape, &shapeTransfer);
-
- shapeTransfer.flags = gxSingleComponentTransfer;
-
- shapeTransfer.component[0].mode = gxBlendMode;
- shapeTransfer.component[1].mode =
- shapeTransfer.component[2].mode =
- shapeTransfer.component[3].mode = 0;
-
- shapeTransfer.component[0].flags = 0;
- shapeTransfer.component[0].sourceMinimum = 0;
- shapeTransfer.component[0].sourceMaximum = 0xFFFF;
- shapeTransfer.component[0].deviceMinimum = 0;
- shapeTransfer.component[0].deviceMaximum = 0xFFFF;
- shapeTransfer.component[0].clampMinimum = 0;
- shapeTransfer.component[0].clampMaximum = 0xFFFF;
- shapeTransfer.component[0].operand = (0xFFFF * theIntensity)/100;
-
- GXSetShapeTransfer(theShape, &shapeTransfer);
- GXGetGraphicsError(&grErr);
- }
-
- ShapeIsNIL:
- UsingFullIntensity:
-
- return grErr;
- }
-
-
- /*******************************************************************
- LoadAPict is a utility routine that just loads a PICT. We
- create a MultiFinder temporary memory handle and return the
- pict in that. This way, we don't impose on the application's
- memory space.
-
- ********************************************************************/
-
- PicHandle LoadAPict(FSSpecPtr opFSSpec)
- {
- OSErr err;
- long count;
- short pictRefNum;
- PicHandle backwashPict = nil;
-
- // Open the file.
-
- err = FSpOpenDF(opFSSpec, fsCurPerm, &pictRefNum);
- nrequire(err, CouldNotOpenFile);
-
- // Get the length of the file minus the 512 byte picture header.
-
- err = GetEOF(pictRefNum, &count);
- nrequire(err, CouldNotGetEOF);
- count -= 512;
-
-
- // Create a handle for our PICT and read the data (Except the header)
- // from the file into the handle.
-
- err = SetFPos(pictRefNum, fsFromStart, 512);
- nrequire(err, CouldNotSetFilePos);
-
- backwashPict = (PicHandle) TempNewHandle(count, &err);
- nrequire(err, CouldNotCreateHandle);
-
- HLock((Handle) backwashPict);
- err = FSRead(pictRefNum, &count, *backwashPict);
- HUnlock((Handle) backwashPict);
-
-
- // If we had an error, kill the picture. Otherwise, just close the file.
-
- if(err)
- {
- KillPicture(backwashPict);
- backwashPict = nil;
- }
-
- CouldNotCreateHandle:
- CouldNotSetFilePos:
- CouldNotGetEOF:
-
- FSClose(pictRefNum);
-
- CouldNotOpenFile:
-
- return backwashPict;
- }
-
-
- /*******************************************************************
- GetJobCollectionItem is a generic routine that retrieves a
- collection item from the job collection.
-
- ********************************************************************/
-
- OSErr GetJobCollectionItem(void *collectItem, long *collectSize,
- OSType collectType, short collectID)
- {
- return GetCollectionItem(GXGetJobCollection(GXGetJob()),
- collectType,
- collectID,
- collectSize,
- collectItem);
- }
-
-
- /*******************************************************************
- HandleSpoolProc is a spooling routine for GXFlattenShape and
- GXUnflattenShape (called from ShapeToHandle and HandleToShape).
- This routine (which was taken from "storage library.c"),
- flattens a gxShape into a handle.
-
- ********************************************************************/
-
- gxGraphicsError HandleSpoolProc(gxSpoolCommand command, UserSpool *block)
- {
- OSErr err = noErr;
-
- switch (command)
- {
- case gxOpenReadSpool: // About to unflatten-- reset the handle size and offset.
-
- block->size = 0;
- block->position = 0;
- break;
-
- case gxOpenWriteSpool: // About to flatten-- create a handle to flatten into,
- // using our initial handle size.
-
- block->data = TempNewHandle(kAllocationIncrement, &err);
- block->size = kAllocationIncrement;
- block->position = 0;
- break;
-
- case gxReadSpool: // Some data has been unflattened. Move the data to
- // our buffer and increase the buffer offset.
-
- BlockMove((*(char **) block->data + block->position), block->spool.buffer, block->spool.count);
- block->position += block->spool.count;
- break;
-
- case gxWriteSpool: // Some data has been flattened.
-
- {
- register long oldPosition;
-
- // If we need to expand the buffer to hold the
- // new data, do so. We always make sure there
- // is enough room for one "bufferSize" past the
- // current point. Move the data to our buffer
- // and increase the buffer offset.
-
- oldPosition = block->position;
- block->position += block->spool.count;
-
- if (block->position + block->spool.bufferSize > block->size)
- {
- block->size += block->spool.bufferSize;
- HUnlock(block->data);
- SetHandleSize(block->data, block->size);
- err = MemError();
- HLock(block->data);
- }
- BlockMove(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count);
- }
- break;
-
- case gxCloseSpool: // Finishing up. Size the buffer to the data's
- // final size.
-
- SetHandleSize(block->data, block->position);
- err = MemError();
- break;
- }
-
- return (gxGraphicsError) err;
- }
-
-
- /*******************************************************************
- ShapeToHandle flattens the passed shape into a handle, which
- it returns. This routine was taken from the "storage library.c"
- file. It simply calls GXFlattenShape with a custom
- gxSpoolProcedure which flattens the shape into a handle.
-
- ********************************************************************/
-
- Handle ShapeToHandle(gxShape source)
- {
- UserSpool block;
-
- block.spool.spoolProcedure = (long (*)(gxSpoolCommand, struct gxSpoolBlock *)) HandleSpoolProc;
- block.spool.buffer = nil;
- block.spool.bufferSize = 0;
- GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten, &block.spool);
- return block.data;
- }
-
-
- /*******************************************************************
- HandleToShape unflattens the passed handle into its original
- gxShape, which it returns. This routine was taken from the
- "storage library.c" file. It simply calls GXUnflattenShape
- with a custom gxSpoolProcedure which unflattens the shape from
- a handle.
-
- ********************************************************************/
-
- gxShape HandleToShape(Handle source, long count, const gxViewPort portList[])
- {
- UserSpool block;
-
- block.spool.spoolProcedure = (long (*)(gxSpoolCommand, struct gxSpoolBlock *)) HandleSpoolProc;
- block.spool.buffer = nil;
- block.spool.bufferSize = 0;
- block.data = source;
- return GXUnflattenShape(&block.spool, count, portList);
- }
-
-
- /*******************************************************************
- PositionWindow - This routine positions a window on the
- screen, centered horizontally and positioned vertPercent
- down the current screen. If showIt is true, we make the
- window visible, otherwise we hide it.
-
- ********************************************************************/
-
- void PositionWindow(WindowPtr windPtr, Boolean showIt, float vertPercent)
- {
- Rect devRect;
- short amtFromTop, windWidth, deviceWidth;
- GDHandle curGDH;
-
- // Get the current GDevice and use its bounds to calculate where we
- // should move the window to.
-
- if (windPtr != nil)
- {
- curGDH = GetGDevice();
- devRect = (*curGDH)->gdRect;
-
- amtFromTop = (devRect.bottom - devRect.top +1) * vertPercent;
- windWidth = windPtr->portRect.right - windPtr->portRect.left +1;
- deviceWidth = devRect.right - devRect.left +1;
-
-
- // Hide the window, move it, and (if we're supposed to) show it again.
-
- ShowHide(windPtr, false);
- MoveWindow(windPtr, devRect.left + (deviceWidth /2 - windWidth /2), devRect.top + amtFromTop, true);
- if (showIt) ShowHide(windPtr, true);
- }
- }
-